package org.jxnd.Test;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.jxnd.bean.Student;


public class Test {
    public static void main(String[] args){
        //XML文件解析 -- 反射动态实现
        /*
         * XML文档动态解析
         *      对象包括数据类型: 八大基本数据类型 String类型 非String对象类型(不支持列表)
         */
        SAXReader reader=new SAXReader();
        //加载XML文档
        Document doc;
        try {
            doc = reader.read(new File("src/Student.xml"));
            Element root=doc.getRootElement();
            
            //创建对象接收列表
            List<Student> stuList = new ArrayList<>();
            
            //通过类和根节点解析XML获取类实例数组
            stuList = getTListByXML(Student.class, root);
            
            for(Student stu : stuList){
                System.out.println(stu);
            }
            System.out.println("OK");
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //获取根节点
    }
    
    /**获取类实例列表 通过解析XML*/
    private static <T> List<T> getTListByXML(Class<T> c, Element root) {
        // TODO Auto-generated method stub
        List<T> tList = new ArrayList<>();
        
        //1.获取根节点下所有子节点
        List<Element> elements = root.elements();
        
        //2.循环遍历子节点
        for(Element e : elements){
          //3.找到与泛型类匹配的节点
            if(e.getName().equals(c.getSimpleName())){
              //4.通过匹配类节点解析XML获取类实例,并添加列表
              T t = null;
              t = getTByXML(c, e);
              tList.add(t);
            }
        }
        return tList;
    }

    /**获取类实例 通过解析XML*/
    private static <T> T getTByXML(Class<T> c, Element root) {
        T t = null;
        try {
            t = c.newInstance();
        } catch (InstantiationException | IllegalAccessException e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
        //1.获取根节点下所有的子类节点
        List<Element> elements = root.elements();
        //2.循环遍历与子节点匹配的set方法
        for(Method method : c.getDeclaredMethods()){
            for(Element e : elements){
                if(method.getName().equalsIgnoreCase("set" + e.getName())){
                    //3.匹配成功,调用方法,为类实例设置
                    try {
                        //此时如果直接调用,将会出现类型不匹配的情况,应先进行数据转换
                        //method.invoke(t, e.getText());不可用
                        //首先要得出set方法参数的数据类型(set方法,参数只有一个)
                        //method.getParameterTypes()[0];
                        //当使用Class的cast方法是将不能进行数据类型转换
                        //我们是将String类型转换为其它数据类型(而cast是父类子类之间的转换)
                        if(e.getText() == "" || e.getText()  == null){
                            continue;
                        }
                        method.invoke(t, stringDataTypeConversion(method.getParameterTypes()[0], e));
                    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
                }
            }
        }
        return t;
    }
    /**数据类型转换 将String类型转换为Class*/
    public static <T> Object stringDataTypeConversion(Class<T> c, Element e){
        switch(c.getSimpleName()){
            case "int" :
            case "Integer" :
                return Integer.parseInt(e.getText());
            case "String" :
                return e.getText();
            case "double" :
            case "Double" :
                return Double.parseDouble(e.getText());
            case "byte" :
            case "Byte" :
                return Byte.parseByte(e.getText());
            case "short" :
            case "Short" :
                return Short.parseShort(e.getText());
            case "long" :
            case "Long" :
                return Long.parseLong(e.getText());
            case "char" :
            case "Character" :
                return e.getText().charAt(0);
            case "folat" :
            case "Float" :
                return Float.parseFloat(e.getText());
            case "boolean" :
            case "Boolean" :
                return Boolean.parseBoolean(e.getText());
            default:
                return getTByXML(c, e);
        }
    }
}



























